Implementación:
La figura muestra el
diagrama
de componentes del patrón CallBack
En la figura del diagrama se muestra la secuencia
del patrón CallBack
Este patrón impone algunos requerimientos
básicos en el cliente y
en el servidor:
- Cliente: el cliente debe proporcionar una interfaz
de retornollamada para el servidor, de forma que este pueda
contactar con el cliente cuando haya finalizado la
petición.
- Servidor: más allá de la interfaz
tradicional del cliente, el servidor necesita alguna forma de
indicar a los clientes
cuando ha acabado el procesamiento. Además, el
servidor debe ser capaz de procesar y, posiblemente,
almacenar las peticiones del cliente.
Ventajas en
inconvenientes:
La mayor ventaja del patrón Callback
es la mejora en la eficiencia
del sistema
especialmente en el rendimiento del servidor. La
mayoría de mejoras se pueden ver en dos áreas
distintas:
- Procesamiento en el servidor: el servidor no tiene
que mantener los threads de comunicación para servir a los
clientes, por lo que puede canalizar esos recursos
hacia peticiones de procesamiento de los clientes o en
atender a llamadores. Además, el servidor puede
realizar el procesamiento cuando lo considere adecuado; no
tiene por que ser el mismo instante que recibe la
petición.
- Comunicación en el servidor: el servidor no
tiene que mantener una conexión abierta mientras el
cliente espera los resultados. Esto significa que un servidor
puede soportar un mayor número de llamadores con unos
recursos de comunicación limitados, como, por ejemplo,
ocurriría con los sockets (conectores).
Esa es precisamente la mayor motivación para utilizar el
patrón CallBack en los sistemas.
En los casos más extremos, puede significar la
diferencia entre tener un grupo de
servidores en
paralelo y utilizar una maquina para atender las peticiones
de los clientes.
Otra ventaja es que el cliente no tiene que esperar
el procesamiento completo del servidor y puede continuar con
otras tareas. El cliente puede seguir con lo que estaba
haciendo mientras espera la respuesta del servidor. Cuando el
resultado esté disponible, éste puede ser
mostrado de forma inmediata.
Dependiendo de la implementación del
patrón, las peticiones de los clientes pueden ponerse en
cola, permitiendo que el servidor organice y priorice su carga
de trabajo.
También permite que el servidor notifique a los clientes
cuando suceden cambios mas halla del tiempo de
vida habitual de un cliente. Los agentes Web son un buen
ejemplo de esto, porque permiten que los clientes introduzcan
una petición en una sesión Web y reciban una
notificación de otra sesión.
Un desafió del patrón Callback es que
necesita que un cliente escuche las retrollamadas del servidor.
Esto a menudo hace que el código del cliente se mas completo, e
incrementa la carga de los sistemas cliente. Un inconveniente
adicional surge del hecho de que Callback desacopla la
petición del cliente. Eso suele dificultar la
cancelación o modificación de una petición
una vez que ha sido enviada al servidor.
Variaciones
del Patrón:
Las variaciones del patrón Callback se centran
generalmente en las estrategias de
procesamiento del servidor y en las aproximaciones sobre las
notificaciones a los clientes. Las dos aproximaciones
principales para el procesamiento en el lado del servidor
son:
- Procesamiento directo: con esta
aproximación, el servidor crea un thread trabajador
para satisfacer las peticiones de los clientes. La
implementación resulta sencilla, pero esto puede ser
complicado de escalar para un gran número de
peticiones de servicio.
- Cola de patrones: el servidor mantiene una cola con
las peticiones de los clientes y un pool de threads
trabajadores. Los threads trabajadores son asignados para
ejecutar el procesamiento de los clientes de forma
continua.
Solo hay opciones disponibles para notificaciones de
los clientes, dependiendo de los requisitos de las
aplicaciones:
- Retrollamada activa: un cliente utiliza un proceso
similar a un servidor para escuchar las comunicaciones entrantes. Eso permite que el
cliente reciba directamente la notificación del
servidor.
- Sondeo del cliente: necesita que el cliente revise
periódicamente el estado
de su petición. Cuando la petición, o una parte
de ella se haya completado, el cliente solicitara la información correspondiente al
servidor.
- Reconocimiento explicito: un servidor puede
retrasmitir un mensaje hasta que recibe una
confirmación del cliente. Esta aproximación se
suele utilizar cuando el procesamiento en el servidor puede
durar un tiempo mucho mayor que el tiempo de vida del
cliente. Aunque esto no es relevante en TCP porque los
sockets no permanecen abiertos a menos que el cliente este
presente para hacer su trabajo, si resulta significativo
cunado se utilizan tecnologías de comunicación
no confiables UDP.
Patrones
relacionados:
Entre lo patrones relacionados con Callback se incluye
Worker Thread. El patrón worker Thread es utilizado para
ayudar a planificar las peticiones de los clientes.
Las peticiones se sitúan en una cola, y los
threads trabajadores procesan.
Ejemplo:
CallbackServer.java
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface CallbackServer extends
Remote{
public void getProject(String projectID, String
callbackMachine,
String callbackObjectName) throws
RemoteException;
}
CallbackServerImpl.java
import java.rmi.Naming;
import java.rmi.server.UnicastRemoteObject;
public class CallbackServerImpl implements
CallbackServer{
private static final String
CALLBACK_SERVER_SERVICE_NAME = "callbackServer";
public CallbackServerImpl(){
try {
UnicastRemoteObject.exportObject(this);
Naming.rebind(CALLBACK_SERVER_SERVICE_NAME,
this);
}
catch (Exception exc){
System.err.println("Error using RMI to register the
CallbackServerImpl " + exc);
}
}
public void getProject(String projectID, String
callbackMachine,
String callbackObjectName){
new CallbackServerDelegate(projectID, callbackMachine,
callbackObjectName);
}
}
CallbackServerDelegate.java
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
public class CallbackServerDelegate implements
Runnable{
private Thread processingThread;
private String projectID;
private String callbackMachine;
private String callbackObjectName;
public CallbackServerDelegate(String newProjectID,
String newCallbackMachine,
String newCallbackObjectName){
projectID = newProjectID;
callbackMachine = newCallbackMachine;
callbackObjectName = newCallbackObjectName;
processingThread = new Thread(this);
processingThread.start();
}
public void run(){
Project result = getProject();
sendProjectToClient(result);
}
private Project getProject(){
return new Project(projectID, "Test
project");
}
private void sendProjectToClient(Project
project){
try{
String url = "//" + callbackMachine + "/" +
callbackObjectName;
Object remoteClient = Naming.lookup(url);
if (remoteClient instanceof
CallbackClient){
((CallbackClient)remoteClient).receiveProject(project);
}
}
catch (RemoteException exc){}
catch (NotBoundException exc){}
catch (MalformedURLException exc){}
}
}
CallbackClient.java
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface CallbackClient extends
Remote{
public void receiveProject(Project project) throws
RemoteException;
}
CallbackClientImpl.java
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.UnknownHostException;
import java.rmi.Naming;
import java.rmi.server.UnicastRemoteObject;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
public class CallbackClientImpl implements
CallbackClient{
private static final String
CALLBACK_CLIENT_SERVICE_NAME = "callbackClient";
private static final String
CALLBACK_SERVER_SERVICE_NAME = "callbackServer";
private static final String
CALLBACK_SERVER_MACHINE_NAME = "localhost";
private Project requestedProject;
private boolean projectAvailable;
public CallbackClientImpl(){
try {
UnicastRemoteObject.exportObject(this);
Naming.rebind(CALLBACK_CLIENT_SERVICE_NAME,
this);
}
catch (Exception exc){
System.err.println("Error using RMI to register the
CallbackClientImpl " + exc);
}
}
public void receiveProject(Project
project){
requestedProject = project;
projectAvailable = true;
}
public void requestProject(String
projectName){
try{
String url = "//" + CALLBACK_SERVER_MACHINE_NAME + "/"
+ CALLBACK_SERVER_SERVICE_NAME;
Object remoteServer = Naming.lookup(url);
if (remoteServer instanceof
CallbackServer){
((CallbackServer)remoteServer).getProject(projectName,
InetAddress.getLocalHost().getHostName(),
CALLBACK_CLIENT_SERVICE_NAME);
}
projectAvailable = false;
}
catch (RemoteException exc){}
catch (NotBoundException exc){}
catch (MalformedURLException exc){}
catch (UnknownHostException exc){}
}
public Project getProject(){ return requestedProject;
}
public boolean isProjectAvailable(){ return
projectAvailable; }
}
Bibliografía:
Patrones de diseño aplicados a JAVA
STEPHEN STELTING /OLAV MAASSEN
Darwin Vélez Vargas
Universidad Tecnológica
Equinoccial
Técnicas Avanzadas de
Programación
2006/06/30
6to "A" Informática
Página anterior | Volver al principio del trabajo | Página siguiente |